<?php
/**
 * @Author: feidao@ibantang.com, 2019, all rights reserved
 * @Date: 2019-11-03
 * @Time: 13:04
 * @Brief:
 */

namespace Core\Common\Model;

use Illuminate\Database\DatabaseManager as IDManager;
use Illuminate\Database\Connection;
use Core\Common\Route\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use InvalidArgumentException;
use App\Utils\Utils;
use PDO;

/**
 * @mixin \Illuminate\Database\Connection
 */
class DatabaseManager extends IDManager
{
    private function getPersistenceId($name)
    {
        if (Request::isRunningInMars()) {
            return "mars." . $name;
        }
        return $name;
    }

    /**
     * Get a database connection instance.
     *
     * @param string $name
     * @return \Illuminate\Database\Connection
     */
    public function connection($name = null)
    {
        list($database, $type) = $this->parseConnectionName($name);

        $name = $name ?: $database;
        $id = $this->getPersistenceId($name);

        // If we haven't created this connection, we'll create it based on the config
        // provided in the application. Once we've created the connections we will
        // set the "fetch mode" for PDO which determines the query return types.
        if (!isset($this->connections[$id])) {
            $this->connections[$id] = $this->configure(
                $this->makeConnection($database),
                $type
            );
        }
        return $this->connections[$id];
    }

//    /**
//     * Parse the connection into an array of the name and read / write type.
//     *
//     * @param string $name
//     * @return array
//     */
//    protected function parseConnectionName($name)
//    {
//        $name = $name ?: $this->getDefaultConnection();
//
//        return Str::endsWith($name, ['::read', '::write'])
//            ? explode('::', $name, 2) : [$name, null];
//    }

//    /**
//     * Make the database connection instance.
//     *
//     * @param string $name
//     * @return \Illuminate\Database\Connection
//     */
//    protected function makeConnection($name)
//    {
//        $config = $this->configuration($name);
//
//        // First we will check by the connection name to see if an extension has been
//        // registered specifically for that connection. If it has we will call the
//        // Closure and pass it the config allowing it to resolve the connection.
//        if (isset($this->extensions[$name])) {
//            return call_user_func($this->extensions[$name], $config, $name);
//        }
//
//        // Next we will check to see if an extension has been registered for a driver
//        // and will call the Closure if so, which allows us to have a more generic
//        // resolver for the drivers themselves which applies to all connections.
//        if (isset($this->extensions[$driver = $config['driver']])) {
//            return call_user_func($this->extensions[$driver], $config, $name);
//        }
//
//        return $this->factory->make($config, $name);
//    }
//
//    /**
//     * Get the configuration for a connection.
//     *
//     * @param string $name
//     * @return array
//     *
//     * @throws \InvalidArgumentException
//     */
//    protected function configuration($name)
//    {
//        $name = $name ?: $this->getDefaultConnection();
//
//        // To get the database connection configuration, we will just pull each of the
//        // connection configurations and get the configurations for the given name.
//        // If the configuration doesn't exist, we'll throw an exception and bail.
//        $connections = $this->app['config']['database.connections'];
//
//        if (is_null($config = Arr::get($connections, $name))) {
//            throw new InvalidArgumentException("Database [$name] not configured.");
//        }
//
//        return $config;
//    }
//
//    /**
//     * Prepare the database connection instance.
//     *
//     * @param \Illuminate\Database\Connection $connection
//     * @param string $type
//     * @return \Illuminate\Database\Connection
//     */
//    protected function configure(Connection $connection, $type)
//    {
//        $connection = $this->setPdoForType($connection, $type);
//
//        // First we'll set the fetch mode and a few other dependencies of the database
//        // connection. This method basically just configures and prepares it to get
//        // used by the application. Once we're finished we'll return it back out.
//        if ($this->app->bound('events')) {
//            $connection->setEventDispatcher($this->app['events']);
//        }
//
//        // Here we'll set a reconnector callback. This reconnector can be any callable
//        // so we will set a Closure to reconnect from this manager with the name of
//        // the connection, which will allow us to reconnect from the connections.
//        $connection->setReconnector(function ($connection) {
//            $this->reconnect($connection->getName());
//        });
//
//        return $connection;
//    }

//    /**
//     * Prepare the read / write mode for database connection instance.
//     *
//     * @param \Illuminate\Database\Connection $connection
//     * @param string $type
//     * @return \Illuminate\Database\Connection
//     */
//    protected function setPdoForType(Connection $connection, $type = null)
//    {
//        if ($type == 'read') {
//            $connection->setPdo($connection->getReadPdo());
//        } elseif ($type == 'write') {
//            $connection->setReadPdo($connection->getPdo());
//        }
//
//        return $connection;
//    }

    /**
     * Disconnect from the given database and remove from local cache.
     *
     * @param string $name
     * @return void
     */
    public function purge($name = null)
    {
        $name = $name ?: $this->getDefaultConnection();
        $id = $this->getPersistenceId($name);
        $this->disconnect($id);
        if (isset($this->connections[$id])) {
            unset($this->connections[$id]);
        }
    }

    /**
     * Disconnect from the given database.
     *
     * @param string $name
     * @return void
     */
    public function disconnect($name = null)
    {
        $name = $name ?: $this->getDefaultConnection();
        $id = $this->getPersistenceId($name);
        if (isset($this->connections[$id])) {
            $this->connections[$id]->disconnect();
        }
    }

    /**
     * Reconnect to the given database.
     *
     * @param string $name
     * @return \Illuminate\Database\Connection
     */
    public function reconnect($name = null)
    {
        $name = $name ?: $this->getDefaultConnection();
        $id = $this->getPersistenceId($name);
        $this->disconnect($name);
        if (!isset($this->connections[$id])) {
            return $this->connection($name);
        }
        return $this->refreshPdoConnections($name);
    }

    /**
     * Refresh the PDO connections on a given connection.
     *
     * @param string $name
     * @return \Illuminate\Database\Connection
     */
    protected function refreshPdoConnections($name)
    {
        $fresh = $this->makeConnection($name);
        $id = $this->getPersistenceId($name);
        return $this->connections[$id]
            ->setPdo($fresh->getPdo())
            ->setReadPdo($fresh->getReadPdo());
    }

//    /**
//     * Set the default connection name.
//     *
//     * @param string $name
//     * @return void
//     */
//    public function setDefaultConnection($name)
//    {
//        $this->app['config']['database.default'] = $name;
//    }
//
//    /**
//     * Get all of the support drivers.
//     *
//     * @return array
//     */
//    public function supportedDrivers()
//    {
//        return ['mysql', 'pgsql', 'sqlite', 'sqlsrv'];
//    }
//
//    /**
//     * Get all of the drivers that are actually available.
//     *
//     * @return array
//     */
//    public function availableDrivers()
//    {
//        return array_intersect(
//            $this->supportedDrivers(),
//            str_replace('dblib', 'sqlsrv', PDO::getAvailableDrivers())
//        );
//    }
//
//    /**
//     * Register an extension connection resolver.
//     *
//     * @param string $name
//     * @param callable $resolver
//     * @return void
//     */
//    public function extend($name, callable $resolver)
//    {
//        $this->extensions[$name] = $resolver;
//    }
}
